home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / program / nasm095s.zip / OUTELF.C < prev    next >
C/C++ Source or Header  |  1997-07-27  |  21KB  |  754 lines

  1. /* outelf.c    output routines for the Netwide Assembler to produce
  2.  *        ELF32 (i386 of course) object file format
  3.  *
  4.  * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
  5.  * Julian Hall. All rights reserved. The software is
  6.  * redistributable under the licence given in the file "Licence"
  7.  * distributed in the NASM archive.
  8.  */
  9.  
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <ctype.h>
  14.  
  15. #include "nasm.h"
  16. #include "nasmlib.h"
  17. #include "outform.h"
  18.  
  19. #ifdef OF_ELF
  20.  
  21. struct Reloc {
  22.     struct Reloc *next;
  23.     long address;               /* relative to _start_ of section */
  24.     long symbol;               /* ELF symbol info thingy */
  25.     int relative;               /* TRUE or FALSE */
  26. };
  27.  
  28. struct Symbol {
  29.     long strpos;               /* string table position of name */
  30.     long section;               /* section ID of the symbol */
  31.     int type;                   /* TRUE or FALSE */
  32.     long value;                   /* address, or COMMON variable size */
  33. };
  34.  
  35. #define SHT_PROGBITS 1
  36. #define SHT_NOBITS 8
  37.  
  38. #define SHF_WRITE 1
  39. #define SHF_ALLOC 2
  40. #define SHF_EXECINSTR 4
  41.  
  42. struct Section {
  43.     struct SAA *data;
  44.     unsigned long len, size, nrelocs;
  45.     long index;
  46.     int type;                   /* SHT_PROGBITS or SHT_NOBITS */
  47.     int align;                   /* alignment: power of two */
  48.     unsigned long flags;           /* section flags */
  49.     char *name;
  50.     struct SAA *rel;
  51.     long rellen;
  52.     struct Reloc *head, **tail;
  53. };
  54.  
  55. #define SECT_DELTA 32
  56. static struct Section **sects;
  57. static int nsects, sectlen;
  58.  
  59. #define SHSTR_DELTA 256
  60. static char *shstrtab;
  61. static int shstrtablen, shstrtabsize;
  62.  
  63. static struct SAA *syms;
  64. static unsigned long nlocals, nglobs;
  65.  
  66. static long def_seg;
  67.  
  68. static struct RAA *bsym;
  69.  
  70. static struct SAA *strs;
  71. static unsigned long strslen;
  72.  
  73. static FILE *elffp;
  74. static efunc error;
  75.  
  76. static char elf_module[FILENAME_MAX];
  77.  
  78. #define SHN_ABS 0xFFF1
  79. #define SHN_COMMON 0xFFF2
  80. #define SHN_UNDEF 0
  81.  
  82. #define SYM_SECTION 0x04
  83. #define SYM_GLOBAL 0x10
  84.  
  85. #define GLOBAL_TEMP_BASE 6           /* bigger than any constant sym id */
  86.  
  87. #define SEG_ALIGN 16               /* alignment of sections in file */
  88. #define SEG_ALIGN_1 (SEG_ALIGN-1)
  89.  
  90. static const char align_str[SEG_ALIGN] = ""; /* ANSI will pad this with 0s */
  91.  
  92. #define ELF_MAX_SECTIONS 16           /* really 10, but let's play safe */
  93. static struct ELF_SECTDATA {
  94.     void *data;
  95.     long len;
  96.     int is_saa;
  97. } elf_sects[ELF_MAX_SECTIONS];
  98. static int elf_nsect;
  99. static long elf_foffs;
  100.  
  101. static void elf_write(void);
  102. static void elf_sect_write(struct Section *, unsigned char *, unsigned long);
  103. static void elf_section_header (int, int, int, void *, int, long,
  104.                 int, int, int, int);
  105. static void elf_write_sections (void);
  106. static struct SAA *elf_build_symtab (long *, long *);
  107. static struct SAA *elf_build_reltab (long *, struct Reloc *);
  108. static void add_sectname (char *, char *);
  109.  
  110. static void elf_init(FILE *fp, efunc errfunc, ldfunc ldef) {
  111.     elffp = fp;
  112.     error = errfunc;
  113.     (void) ldef;               /* placate optimisers */
  114.     sects = NULL;
  115.     nsects = sectlen = 0;
  116.     syms = saa_init((long)sizeof(struct Symbol));
  117.     nlocals = nglobs = 0;
  118.     bsym = raa_init();
  119.     strs = saa_init(1L);
  120.     saa_wbytes (strs, "\0", 1L);
  121.     saa_wbytes (strs, elf_module, (long)(strlen(elf_module)+1));
  122.     strslen = 2+strlen(elf_module);
  123.     shstrtab = NULL;
  124.     shstrtablen = shstrtabsize = 0;;
  125.     add_sectname ("", "");
  126.     def_seg = seg_alloc();
  127. }
  128.  
  129. static void elf_cleanup(void) {
  130.     struct Reloc *r;
  131.     int i;
  132.  
  133.     elf_write();
  134.     fclose (elffp);
  135.     for (i=0; i<nsects; i++) {
  136.     if (sects[i]->type != SHT_NOBITS)
  137.         saa_free (sects[i]->data);
  138.     if (sects[i]->head)
  139.         saa_free (sects[i]->rel);
  140.     while (sects[i]->head) {
  141.         r = sects[i]->head;
  142.         sects[i]->head = sects[i]->head->next;
  143.         nasm_free (r);
  144.     }
  145.     }
  146.     nasm_free (sects);
  147.     saa_free (syms);
  148.     raa_free (bsym);
  149.     saa_free (strs);
  150. }
  151.  
  152. static void add_sectname (char *firsthalf, char *secondhalf) {
  153.     int len = strlen(firsthalf)+strlen(secondhalf);
  154.     while (shstrtablen + len + 1 > shstrtabsize)
  155.     shstrtab = nasm_realloc (shstrtab, (shstrtabsize += SHSTR_DELTA));
  156.     strcpy (shstrtab+shstrtablen, firsthalf);
  157.     strcat (shstrtab+shstrtablen, secondhalf);
  158.     shstrtablen += len+1;
  159. }
  160.  
  161. static int elf_make_section (char *name, int type, int flags, int align) {
  162.     struct Section *s;
  163.  
  164.     s = nasm_malloc (sizeof(*s));
  165.  
  166.     if (type != SHT_NOBITS)
  167.     s->data = saa_init (1L);
  168.     s->head = NULL;
  169.     s->tail = &s->head;
  170.     s->len = s->size = 0;
  171.     s->nrelocs = 0;
  172.     if (!strcmp(name, ".text"))
  173.     s->index = def_seg;
  174.     else
  175.     s->index = seg_alloc();
  176.     add_sectname ("", name);
  177.     s->name = nasm_malloc (1+strlen(name));
  178.     strcpy (s->name, name);
  179.     s->type = type;
  180.     s->flags = flags;
  181.     s->align = align;
  182.  
  183.     if (nsects >= sectlen)
  184.     sects = nasm_realloc (sects, (sectlen += SECT_DELTA)*sizeof(*sects));
  185.     sects[nsects++] = s;
  186.  
  187.     return nsects-1;
  188. }
  189.  
  190. static long elf_section_names (char *name, int pass, int *bits) {
  191.     char *p;
  192.     int flags_and, flags_or, type, align, i;
  193.  
  194.     /*
  195.      * Default is 32 bits.
  196.      */
  197.     if (!name)
  198.     *bits = 32;
  199.  
  200.     if (!name)
  201.     return def_seg;
  202.  
  203.     p = name;
  204.     while (*p && !isspace(*p)) p++;
  205.     if (*p) *p++ = '\0';
  206.     flags_and = flags_or = type = align = 0;
  207.  
  208.     while (*p && isspace(*p)) p++;
  209.     while (*p) {
  210.     char *q = p;
  211.     while (*p && !isspace(*p)) p++;
  212.     if (*p) *p++ = '\0';
  213.     while (*p && isspace(*p)) p++;
  214.     
  215.     if (!nasm_strnicmp(q, "align=", 6)) {
  216.         align = atoi(q+6);
  217.         if (align == 0)
  218.         align = 1;
  219.         if ( (align-1) & align ) {   /* means it's not a power of two */
  220.         error (ERR_NONFATAL, "section alignment %d is not"
  221.                " a power of two", align);
  222.         align = 1;
  223.         }
  224.     } else if (!nasm_stricmp(q, "alloc")) {
  225.         flags_and |= SHF_ALLOC;
  226.         flags_or |= SHF_ALLOC;
  227.     } else if (!nasm_stricmp(q, "noalloc")) {
  228.         flags_and |= SHF_ALLOC;
  229.         flags_or &= ~SHF_ALLOC;
  230.     } else if (!nasm_stricmp(q, "exec")) {
  231.         flags_and |= SHF_EXECINSTR;
  232.         flags_or |= SHF_EXECINSTR;
  233.     } else if (!nasm_stricmp(q, "noexec")) {
  234.         flags_and |= SHF_EXECINSTR;
  235.         flags_or &= ~SHF_EXECINSTR;
  236.     } else if (!nasm_stricmp(q, "write")) {
  237.         flags_and |= SHF_WRITE;
  238.         flags_or |= SHF_WRITE;
  239.     } else if (!nasm_stricmp(q, "nowrite")) {
  240.         flags_and |= SHF_WRITE;
  241.         flags_or &= ~SHF_WRITE;
  242.     } else if (!nasm_stricmp(q, "progbits")) {
  243.         type = SHT_PROGBITS;
  244.     } else if (!nasm_stricmp(q, "nobits")) {
  245.         type = SHT_NOBITS;
  246.     }
  247.     }
  248.  
  249.     if (!strcmp(name, ".comment") ||
  250.     !strcmp(name, ".shstrtab") ||
  251.     !strcmp(name, ".symtab") ||
  252.     !strcmp(name, ".strtab")) {
  253.     error (ERR_NONFATAL, "attempt to redefine reserved section"
  254.            "name `%s'", name);
  255.     return NO_SEG;
  256.     }
  257.  
  258.     for (i=0; i<nsects; i++)
  259.     if (!strcmp(name, sects[i]->name))
  260.         break;
  261.     if (i == nsects) {
  262.     if (!strcmp(name, ".text"))
  263.         i = elf_make_section (name, SHT_PROGBITS,
  264.                   SHF_ALLOC | SHF_EXECINSTR, 16);
  265.     else if (!strcmp(name, ".data"))
  266.         i = elf_make_section (name, SHT_PROGBITS,
  267.                   SHF_ALLOC | SHF_WRITE, 4);
  268.     else if (!strcmp(name, ".bss"))
  269.         i = elf_make_section (name, SHT_NOBITS,
  270.                   SHF_ALLOC | SHF_WRITE, 4);
  271.     else
  272.         i = elf_make_section (name, SHT_PROGBITS, SHF_ALLOC, 1);
  273.     if (type)
  274.         sects[i]->type = type;
  275.     if (align)
  276.         sects[i]->align = align;
  277.     sects[i]->flags &= ~flags_and;
  278.     sects[i]->flags |= flags_or;
  279.     } else if (pass == 1) {
  280.     if (type || align || flags_and)
  281.         error (ERR_WARNING, "section attributes ignored on"
  282.            " redeclaration of section `%s'", name);
  283.     }
  284.  
  285.     return sects[i]->index;
  286. }
  287.  
  288. static void elf_deflabel (char *name, long segment, long offset,
  289.                int is_global) {
  290.     int pos = strslen;
  291.     struct Symbol *sym;
  292.  
  293.     if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
  294.     error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
  295.     return;
  296.     }
  297.  
  298.     saa_wbytes (strs, name, (long)(1+strlen(name)));
  299.     strslen += 1+strlen(name);
  300.  
  301.     sym = saa_wstruct (syms);
  302.  
  303.     sym->strpos = pos;
  304.     sym->type = is_global ? SYM_GLOBAL : 0;
  305.     if (segment == NO_SEG)
  306.     sym->section = SHN_ABS;
  307.     else {
  308.     int i;
  309.     sym->section = SHN_UNDEF;
  310.     if (nsects == 0 && segment == def_seg) {
  311.         int tempint;
  312.         if (segment != elf_section_names (".text", 2, &tempint))
  313.         error (ERR_PANIC, "strange segment conditions in ELF driver");
  314.         sym->section = nsects;
  315.     } else {
  316.         for (i=0; i<nsects; i++)
  317.         if (segment == sects[i]->index) {
  318.             sym->section = i+1;
  319.             break;
  320.         }
  321.     }
  322.     }
  323.  
  324.     if (is_global == 2) {
  325.     sym->value = offset;
  326.     sym->section = SHN_COMMON;
  327.     } else
  328.     sym->value = (sym->section == SHN_UNDEF ? 0 : offset);
  329.  
  330.     if (sym->type == SYM_GLOBAL) {
  331.     if (sym->section == SHN_UNDEF || sym->section == SHN_COMMON)
  332.         bsym = raa_write (bsym, segment, nglobs);
  333.     nglobs++;
  334.     } else
  335.     nlocals++;
  336. }
  337.  
  338. static void elf_add_reloc (struct Section *sect, long segment,
  339.                 int relative) {
  340.     struct Reloc *r;
  341.  
  342.     r = *sect->tail = nasm_malloc(sizeof(struct Reloc));
  343.     sect->tail = &r->next;
  344.     r->next = NULL;
  345.  
  346.     r->address = sect->len;
  347.     if (segment == NO_SEG)
  348.     r->symbol = 2;
  349.     else {
  350.     int i;
  351.     r->symbol = 0;
  352.     for (i=0; i<nsects; i++)
  353.         if (segment == sects[i]->index)
  354.         r->symbol = i+3;
  355.     if (!r->symbol)
  356.         r->symbol = GLOBAL_TEMP_BASE + raa_read(bsym, segment);
  357.     }
  358.     r->relative = relative;
  359.  
  360.     sect->nrelocs++;
  361. }
  362.  
  363. static void elf_out (long segto, void *data, unsigned long type,
  364.               long segment, long wrt) {
  365.     struct Section *s;
  366.     long realbytes = type & OUT_SIZMASK;
  367.     unsigned char mydata[4], *p;
  368.     int i;
  369.  
  370.     if (wrt != NO_SEG) {
  371.     wrt = NO_SEG;               /* continue to do _something_ */
  372.     error (ERR_NONFATAL, "WRT not supported by ELF output format");
  373.     }
  374.  
  375.     type &= OUT_TYPMASK;
  376.  
  377.     /*
  378.      * handle absolute-assembly (structure definitions)
  379.      */
  380.     if (segto == NO_SEG) {
  381.     if (type != OUT_RESERVE)
  382.         error (ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]"
  383.            " space");
  384.     return;
  385.     }
  386.  
  387.     s = NULL;
  388.     for (i=0; i<nsects; i++)
  389.     if (segto == sects[i]->index) {
  390.         s = sects[i];
  391.         break;
  392.     }
  393.     if (!s) {
  394.     int tempint;               /* ignored */
  395.     if (segto != elf_section_names (".text", 2, &tempint))
  396.         error (ERR_PANIC, "strange segment conditions in ELF driver");
  397.     else
  398.         s = sects[nsects-1];
  399.     }
  400.  
  401.     if (s->type == SHT_NOBITS && type != OUT_RESERVE) {
  402.     error(ERR_WARNING, "attempt to initialise memory in"
  403.           " BSS section `%s': ignored", s->name);
  404.     if (type == OUT_REL2ADR)
  405.         realbytes = 2;
  406.     else if (type == OUT_REL4ADR)
  407.         realbytes = 4;
  408.     s->len += realbytes;
  409.     return;
  410.     }
  411.  
  412.     if (type == OUT_RESERVE) {
  413.     if (s->type == SHT_PROGBITS) {
  414.         error(ERR_WARNING, "uninitialised space declared in"
  415.           " non-BSS section `%s': zeroing", s->name);
  416.         elf_sect_write (s, NULL, realbytes);
  417.     } else
  418.         s->len += realbytes;
  419.     } else if (type == OUT_RAWDATA) {
  420.     if (segment != NO_SEG)
  421.         error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG");
  422.     elf_sect_write (s, data, realbytes);
  423.     } else if (type == OUT_ADDRESS) {
  424.     if (wrt != NO_SEG)
  425.         error(ERR_NONFATAL, "ELF format does not support WRT types");
  426.     if (segment != NO_SEG) {
  427.         if (segment % 2) {
  428.         error(ERR_NONFATAL, "ELF format does not support"
  429.               " segment base references");
  430.         } else
  431.         elf_add_reloc (s, segment, FALSE);
  432.     }
  433.     p = mydata;
  434.     if (realbytes == 2 && segment != NO_SEG)
  435.         error (ERR_NONFATAL, "ELF format does not support 16-bit"
  436.            " relocations");
  437.     WRITELONG (p, *(long *)data);
  438.     elf_sect_write (s, mydata, realbytes);
  439.     } else if (type == OUT_REL2ADR) {
  440.     error (ERR_NONFATAL, "ELF format does not support 16-bit"
  441.            " relocations");
  442.     } else if (type == OUT_REL4ADR) {
  443.     if (segment == segto)
  444.         error(ERR_PANIC, "intra-segment OUT_REL4ADR");
  445.     if (segment != NO_SEG && segment % 2) {
  446.         error(ERR_NONFATAL, "ELF format does not support"
  447.           " segment base references");
  448.     } else
  449.         elf_add_reloc (s, segment, TRUE);
  450.     p = mydata;
  451.     WRITELONG (p, *(long*)data - realbytes);
  452.     elf_sect_write (s, mydata, 4L);
  453.     }
  454. }
  455.  
  456. static void elf_write(void) {
  457.     int nsections, align;
  458.     char *p;
  459.     int commlen;
  460.     char comment[64];
  461.     int i;
  462.  
  463.     struct SAA *symtab;
  464.     long symtablen, symtablocal;
  465.  
  466.     /*
  467.      * Work out how many sections we will have. We have SHN_UNDEF,
  468.      * then the flexible user sections, then the four fixed
  469.      * sections `.comment', `.shstrtab', `.symtab' and `.strtab',
  470.      * then optionally relocation sections for the user sections.
  471.      */
  472.     nsections = 5;               /* SHN_UNDEF and the fixed ones */
  473.     add_sectname ("", ".comment");
  474.     add_sectname ("", ".shstrtab");
  475.     add_sectname ("", ".symtab");
  476.     add_sectname ("", ".strtab");
  477.     for (i=0; i<nsects; i++) {
  478.     nsections++;               /* for the section itself */
  479.     if (sects[i]->head) {
  480.         nsections++;           /* for its relocations */
  481.         add_sectname (".rel", sects[i]->name);
  482.     }
  483.     }
  484.  
  485.     /*
  486.      * Do the comment.
  487.      */
  488.     *comment = '\0';
  489.     commlen = 2+sprintf(comment+1, "The Netwide Assembler %s", NASM_VER);
  490.  
  491.     /*
  492.      * Output the ELF header.
  493.      */
  494.     fwrite ("\177ELF\1\1\1\0\0\0\0\0\0\0\0\0", 16, 1, elffp);
  495.     fwriteshort (1, elffp);           /* ET_REL relocatable file */
  496.     fwriteshort (3, elffp);           /* EM_386 processor ID */
  497.     fwritelong (1L, elffp);           /* EV_CURRENT file format version */
  498.     fwritelong (0L, elffp);           /* no entry point */
  499.     fwritelong (0L, elffp);           /* no program header table */
  500.     fwritelong (0x40L, elffp);           /* section headers straight after
  501.                     * ELF header plus alignment */
  502.     fwritelong (0L, elffp);           /* 386 defines no special flags */
  503.     fwriteshort (0x34, elffp);           /* size of ELF header */
  504.     fwriteshort (0, elffp);           /* no program header table, again */
  505.     fwriteshort (0, elffp);           /* still no program header table */
  506.     fwriteshort (0x28, elffp);           /* size of section header */
  507.     fwriteshort (nsections, elffp);    /* number of sections */
  508.     fwriteshort (nsects+2, elffp);     /* string table section index for
  509.                     * section header table */
  510.     fwritelong (0L, elffp);           /* align to 0x40 bytes */
  511.     fwritelong (0L, elffp);
  512.     fwritelong (0L, elffp);
  513.  
  514.     /*
  515.      * Build the symbol table and relocation tables.
  516.      */
  517.     symtab = elf_build_symtab (&symtablen, &symtablocal);
  518.     for (i=0; i<nsects; i++)
  519.     if (sects[i]->head)
  520.         sects[i]->rel = elf_build_reltab (§s[i]->rellen,
  521.                           sects[i]->head);
  522.  
  523.     /*
  524.      * Now output the section header table.
  525.      */
  526.  
  527.     elf_foffs = 0x40 + 0x28 * nsections;
  528.     align = ((elf_foffs+SEG_ALIGN_1) & ~SEG_ALIGN_1) - elf_foffs;
  529.     elf_foffs += align;
  530.     elf_nsect = 0;
  531.  
  532.     elf_section_header (0, 0, 0, NULL, FALSE, 0L, 0, 0, 0, 0); /* SHN_UNDEF */
  533.     p = shstrtab+1;
  534.     for (i=0; i<nsects; i++) {
  535.     elf_section_header (p - shstrtab, sects[i]->type, sects[i]->flags,
  536.                 (sects[i]->type == SHT_PROGBITS ?
  537.                  sects[i]->data : NULL), TRUE,
  538.                 sects[i]->len, 0, 0, sects[i]->align, 0);
  539.     p += strlen(p)+1;
  540.     }
  541.     elf_section_header (p - shstrtab, 1, 0, comment, FALSE,
  542.             (long)commlen, 0, 0, 1, 0);/* .comment */
  543.     p += strlen(p)+1;
  544.     elf_section_header (p - shstrtab, 3, 0, shstrtab, FALSE,
  545.             (long)shstrtablen, 0, 0, 1, 0);/* .shstrtab */
  546.     p += strlen(p)+1;
  547.     elf_section_header (p - shstrtab, 2, 0, symtab, TRUE,
  548.             symtablen, nsects+4, symtablocal, 4, 16);/* .symtab */
  549.     p += strlen(p)+1;
  550.     elf_section_header (p - shstrtab, 3, 0, strs, TRUE,
  551.             strslen, 0, 0, 1, 0);        /* .strtab */
  552.     for (i=0; i<nsects; i++) if (sects[i]->head) {
  553.     p += strlen(p)+1;
  554.     elf_section_header (p - shstrtab, 9, 0, sects[i]->rel, TRUE,
  555.                 sects[i]->rellen, nsects+3, i+1, 4, 8);
  556.     }
  557.  
  558.     fwrite (align_str, align, 1, elffp);
  559.  
  560.     /*
  561.      * Now output the sections.
  562.      */
  563.     elf_write_sections();
  564.  
  565.     saa_free (symtab);
  566. }
  567.  
  568. static struct SAA *elf_build_symtab (long *len, long *local) {
  569.     struct SAA *s = saa_init(1L);
  570.     struct Symbol *sym;
  571.     unsigned char entry[16], *p;
  572.     int i;
  573.  
  574.     *len = *local = 0;
  575.  
  576.     /*
  577.      * First, an all-zeros entry, required by the ELF spec.
  578.      */
  579.     saa_wbytes (s, NULL, 16L);           /* null symbol table entry */
  580.     *len += 16;
  581.     (*local)++;
  582.  
  583.     /*
  584.      * Next, an entry for the file name.
  585.      */
  586.     p = entry;
  587.     WRITELONG (p, 1);               /* we know it's 1st thing in strtab */
  588.     WRITELONG (p, 0);               /* no value */
  589.     WRITELONG (p, 0);               /* no size either */
  590.     WRITESHORT (p, 4);               /* type FILE */
  591.     WRITESHORT (p, SHN_ABS);
  592.     saa_wbytes (s, entry, 16L);
  593.     *len += 16;
  594.     (*local)++;
  595.  
  596.     /*
  597.      * Now some standard symbols defining the segments, for relocation
  598.      * purposes.
  599.      */
  600.     for (i = 1; i <= nsects+1; i++) {
  601.     p = entry;
  602.     WRITELONG (p, 0);           /* no symbol name */
  603.     WRITELONG (p, 0);           /* offset zero */
  604.     WRITELONG (p, 0);           /* size zero */
  605.     WRITESHORT (p, 3);           /* local section-type thing */
  606.     WRITESHORT (p, (i==1 ? SHN_ABS : i-1));   /* the section id */
  607.     saa_wbytes (s, entry, 16L);
  608.     *len += 16;
  609.     (*local)++;
  610.     }
  611.  
  612.     /*
  613.      * Now the other local symbols.
  614.      */
  615.     saa_rewind (syms);
  616.     while ( (sym = saa_rstruct (syms)) ) {
  617.     if (sym->type == SYM_GLOBAL)
  618.         continue;
  619.     p = entry;
  620.     WRITELONG (p, sym->strpos);
  621.     WRITELONG (p, sym->value);
  622.     if (sym->section == SHN_COMMON)
  623.         WRITELONG (p, sym->value);
  624.     else
  625.         WRITELONG (p, 0);
  626.     WRITESHORT (p, 0);           /* local non-typed thing */
  627.     WRITESHORT (p, sym->section);
  628.     saa_wbytes (s, entry, 16L);
  629.         *len += 16;
  630.     (*local)++;
  631.     }
  632.  
  633.     /*
  634.      * Now the global symbols.
  635.      */
  636.     saa_rewind (syms);
  637.     while ( (sym = saa_rstruct (syms)) ) {
  638.     if (sym->type != SYM_GLOBAL)
  639.         continue;
  640.     p = entry;
  641.     WRITELONG (p, sym->strpos);
  642.     WRITELONG (p, sym->value);
  643.     if (sym->section == SHN_COMMON)
  644.         WRITELONG (p, sym->value);
  645.     else
  646.         WRITELONG (p, 0);
  647.     WRITESHORT (p, SYM_GLOBAL);    /* global non-typed thing */
  648.     WRITESHORT (p, sym->section);
  649.     saa_wbytes (s, entry, 16L);
  650.     *len += 16;
  651.     }
  652.  
  653.     return s;
  654. }
  655.  
  656. static struct SAA *elf_build_reltab (long *len, struct Reloc *r) {
  657.     struct SAA *s;
  658.     unsigned char *p, entry[8];
  659.  
  660.     if (!r)
  661.     return NULL;
  662.  
  663.     s = saa_init(1L);
  664.     *len = 0;
  665.  
  666.     while (r) {
  667.     long sym = r->symbol;
  668.  
  669.     if (sym >= GLOBAL_TEMP_BASE)
  670.         sym += -GLOBAL_TEMP_BASE + (nsects+3) + nlocals;
  671.  
  672.     p = entry;
  673.     WRITELONG (p, r->address);
  674.     WRITELONG (p, (sym << 8) + (r->relative ? 2 : 1));
  675.     saa_wbytes (s, entry, 8L);
  676.     *len += 8;
  677.  
  678.     r = r->next;
  679.     }
  680.  
  681.     return s;
  682. }
  683.  
  684. static void elf_section_header (int name, int type, int flags,
  685.                 void *data, int is_saa, long datalen,
  686.                 int link, int info, int align, int eltsize) {
  687.     elf_sects[elf_nsect].data = data;
  688.     elf_sects[elf_nsect].len = datalen;
  689.     elf_sects[elf_nsect].is_saa = is_saa;
  690.     elf_nsect++;
  691.  
  692.     fwritelong ((long)name, elffp);
  693.     fwritelong ((long)type, elffp);
  694.     fwritelong ((long)flags, elffp);
  695.     fwritelong (0L, elffp);           /* no address, ever, in object files */
  696.     fwritelong (type == 0 ? 0L : elf_foffs, elffp);
  697.     fwritelong (datalen, elffp);
  698.     if (data)
  699.     elf_foffs += (datalen+SEG_ALIGN_1) & ~SEG_ALIGN_1;
  700.     fwritelong ((long)link, elffp);
  701.     fwritelong ((long)info, elffp);
  702.     fwritelong ((long)align, elffp);
  703.     fwritelong ((long)eltsize, elffp);
  704. }
  705.  
  706. static void elf_write_sections (void) {
  707.     int i;
  708.     for (i = 0; i < elf_nsect; i++)
  709.     if (elf_sects[i].data) {
  710.         long len = elf_sects[i].len;
  711.         long reallen = (len+SEG_ALIGN_1) & ~SEG_ALIGN_1;
  712.         long align = reallen - len;
  713.         if (elf_sects[i].is_saa)
  714.         saa_fpwrite (elf_sects[i].data, elffp);
  715.         else
  716.         fwrite (elf_sects[i].data, len, 1, elffp);
  717.         fwrite (align_str, align, 1, elffp);
  718.     }
  719. }
  720.  
  721. static void elf_sect_write (struct Section *sect,
  722.                  unsigned char *data, unsigned long len) {
  723.     saa_wbytes (sect->data, data, len);
  724.     sect->len += len;
  725. }
  726.  
  727. static long elf_segbase (long segment) {
  728.     return segment;
  729. }
  730.  
  731. static int elf_directive (char *directive, char *value, int pass) {
  732.     return 0;
  733. }
  734.  
  735. static void elf_filename (char *inname, char *outname, efunc error) {
  736.     strcpy(elf_module, inname);
  737.     standard_extension (inname, outname, ".o", error);
  738. }
  739.  
  740. struct ofmt of_elf = {
  741.     "ELF32 (i386) object files (e.g. Linux)",
  742.     "elf",
  743.     elf_init,
  744.     elf_out,
  745.     elf_deflabel,
  746.     elf_section_names,
  747.     elf_segbase,
  748.     elf_directive,
  749.     elf_filename,
  750.     elf_cleanup
  751. };
  752.  
  753. #endif /* OF_ELF */
  754.